package com.gzhryc.shared_device.bxscn.code.services;

import com.gzhryc.common.StringTools;
import com.gzhryc.common.exceptions.LogicException;
import com.gzhryc.common.logging.Logger;
import com.gzhryc.jdbc.Conditions;
import com.gzhryc.jdbc.JdbcSession;
import com.gzhryc.jdbc.MultiDBTools;
import com.gzhryc.shared_device.base.IPlaceService;
import com.gzhryc.shared_device.base.models.IPlace;
import com.gzhryc.shared_device.bxscn.code.dao.PortableEnergyBatteryDao;
import com.gzhryc.shared_device.bxscn.code.dao.db.PortableEnergyBattery;
import com.gzhryc.shared_device.bxscn.code.dao.db.PortableEnergyBatteryType;
import com.gzhryc.shared_device.bxscn.code.dao.enums.PortableEnergyBatteryEnum;
import com.gzhryc.shared_device.bxscn.code.dao.models.PortableEnergyBatteryPlaceCount;
import com.gzhryc.shared_device.bxscn.code.dao.models.PortableEnergyBatteryTypeCount;
import com.gzhryc.shared_device.bxscn.code.services.dto.PortableEnergyBatterySearch;
import com.gzhryc.shared_device.bxscn.core.BXSCNConstants;

import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class PortableEnergyBatteryService {

	static Logger log = Logger.getLogger(PortableEnergyBatteryService.class);

	public static PortableEnergyBatteryService self() {
		return MultiDBTools.getService(PortableEnergyBatteryService.class, true);
	}

	public static PortableEnergyBatteryService self(String jdbcKey) {
		return MultiDBTools.getService(jdbcKey, PortableEnergyBatteryService.class, true);
	}

	PortableEnergyBatteryDao dao;

	public PortableEnergyBatteryService(String jdbcKey) {
		this.dao = new PortableEnergyBatteryDao(jdbcKey);
	}

	public List<PortableEnergyBattery> findBySearch(PortableEnergyBatterySearch search, Integer pageNo, Integer pageLimit){
		Conditions conditions = dao.buildConditions(search);
		conditions.and().in("placeId",search.getPlaceIds());

		try {
			return dao.findByCondition(conditions,pageNo,pageLimit);
		} catch (SQLException e) {
			log.error(e.getMessage(),e);
		}
		return null;
	}

	public List<PortableEnergyBattery> findJoinBySearch(PortableEnergyBatterySearch search, Integer pageNo, Integer pageLimit){
		Conditions conditions = dao.buildConditions(search);
		conditions.and().in("placeId",search.getPlaceIds());

		try {
			return dao.findJoinByCondition(conditions,pageNo,pageLimit);
		} catch (SQLException e) {
			log.error(e.getMessage(),e);
		}
		return null;
	}

	public Long countJoinBySearch(PortableEnergyBatterySearch search){
		Conditions conditions = dao.buildConditions(search);
		conditions.and().in("placeId",search.getPlaceIds());

		try {
			return dao.countJoin(conditions);
		} catch (SQLException e) {
			log.error(e.getMessage(),e);
		}
		return 0L;
	}

	public Long countByBatteryType(String batteryType){
		if(StringTools.isNotBlank(batteryType)){
			Conditions conditions = new Conditions(PortableEnergyBattery.class);
			conditions.and().is("type",batteryType);

			try {
				return dao.count(conditions);
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}
		}
		return 0L;
	}

	public Long countByPlaceId(Long placeId){
		if(placeId != null){
			Conditions conditions = new Conditions(PortableEnergyBattery.class);
			conditions.and().is("placeId",placeId);

			try {
				return dao.count(conditions);
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}
		}
		return 0L;
	}

	public Long countChargingByPlaceIdAndBatteryType(Long placeId,String batteryType){
		Conditions conditions = new Conditions(PortableEnergyBattery.class);
		conditions.and().is("placeId",placeId);
		conditions.and().is("type",batteryType);
		conditions.and().is("state",PortableEnergyBatteryEnum.State.Charging.index());
		try {
			return dao.count(conditions);
		} catch (SQLException e) {
			log.error(e.getMessage(), e);
		}
		return 0L;
	}

	public List<PortableEnergyBatteryTypeCount> findTypeCountByPlaceId(Long placeId){
		if(placeId != null){
			Conditions conditions = new Conditions(PortableEnergyBattery.class);
			conditions.and().is("placeId",placeId);

			try {
				return dao.groupTypeByConditions(conditions);
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}
		}
		return null;
	}

	public List<PortableEnergyBatteryTypeCount> findTypeCountByStateAndTypeIds(Integer state,List<String> batteryTypeList){
		if(batteryTypeList != null && batteryTypeList.size() > 0 && state != null){
			Conditions conditions = new Conditions(PortableEnergyBattery.class);
			conditions.and().in("type",batteryTypeList);
			conditions.and().is("state",state);

			try {
				return dao.groupTypeByConditions(conditions);
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}
		}
		return null;
	}

	public List<PortableEnergyBatteryPlaceCount> findPlaceCountByStateAndTypeIdAndPlaceIds(Integer state, String batteryType, List<Long> placeIds){
		if(placeIds != null && placeIds.size() > 0 && state != null && StringTools.isNotBlank(batteryType)){
			Conditions conditions = new Conditions(PortableEnergyBattery.class);
			conditions.and().is("type",batteryType);
			conditions.and().is("state",state);
			conditions.and().in("placeId",placeIds);

			try {
				return dao.groupPlaceByConditions(conditions);
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}
		}
		return null;
	}

	public List<PortableEnergyBatteryPlaceCount> findPlaceCountByPlaceIds(List<Long> placeIds){
		if(placeIds != null && placeIds.size() > 0){
			Conditions conditions = new Conditions(PortableEnergyBattery.class);
			conditions.and().in("placeId",placeIds);

			try {
				return dao.groupPlaceByConditions(conditions);
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}
		}
		return null;
	}

	public List<Long> findPlaceIdByBatteryTypeAndLeaseType(String batteryType,Integer leaseType,Integer pageNo,Integer pageLimit){
		if(StringTools.isNotBlank(batteryType) && leaseType != null){
			Conditions conditions = new Conditions(PortableEnergyBattery.class);
			conditions.and().is("type",batteryType);
			conditions.and().is("leaseType",leaseType);
			conditions.and().isNotNull("placeId");

			try {
				return dao.findOnlyPlaceIdByConditions(conditions,pageNo,pageLimit);
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}
		}
		return null;
	}

	public List<PortableEnergyBattery> findByPlaceId(Long placeId){
		if(placeId != null){
			Conditions conditions = new Conditions(PortableEnergyBattery.class);
			conditions.and().is("placeId",placeId);

			try {
				return dao.findByCondition(conditions);
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}
		}
		return null;
	}

	public List<PortableEnergyBattery> findJoinByPlaceId(Long placeId){
		if(placeId != null){
			Conditions conditions = new Conditions(PortableEnergyBattery.class);
			conditions.and().is("placeId",placeId);

			try {
				return dao.findJoinByCondition(conditions);
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}
		}
		return null;
	}

	
	public List<String> findBatteryTypeByPlaceId(Long placeId){
		if(placeId != null){
			Conditions conditions = new Conditions(PortableEnergyBattery.class);
			conditions.and().is("placeId",placeId);

			try {
				return dao.findOnlyBatteryTypeByConditions(conditions);
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}
		}
		return null;
	}

	public PortableEnergyBattery getByDeviceSn(String deviceSn){
		try {
			return dao.getById(deviceSn);
		} catch (SQLException e) {
			log.error(e.getMessage(),e);
		}
		return null;
	}

	public PortableEnergyBattery getJoinByDeviceSn(String deviceSn){
		try {
			return dao.getJoinById(deviceSn);
		} catch (SQLException e) {
			log.error(e.getMessage(),e);
		}
		return null;
	}

	public boolean add(PortableEnergyBattery portableBattery) throws LogicException{
		if(StringTools.isBlank(portableBattery.getDeviceSn()) || portableBattery.getDeviceSn().length() < 6) {
			throw new LogicException("电池序列号需要5位数以上");
		}
		portableBattery.setCreateDate(new Date());
		if(StringTools.isBlank(portableBattery.getType())){
			throw new LogicException("设备类型未空");
		}
		if(StringTools.isBlank(portableBattery.getTypeName()) || portableBattery.getBatteryPower() == null){
			PortableEnergyBatteryType batteryType = PortableEnergyBatteryTypeService.self()
					.getById(portableBattery.getType());
			if(batteryType == null){
				throw new LogicException("未找到设备类型：" + portableBattery.getType());
			}
			portableBattery.setTypeName(batteryType.getName());
			portableBattery.setBatteryPower(batteryType.getBatteryPower());
		}
		try {
			return dao.insert(portableBattery) > 0;
		} catch (SQLException e) {
			log.error(e.getMessage(),e);
		}
		return false;
	}

	public boolean deploy(PortableEnergyBattery portableBattery, IPlace place,String bindNote,IPlaceService placeService) throws LogicException {
		if(portableBattery != null && place != null && place.getId() != null){
			PortableEnergyBattery updateEntity = new PortableEnergyBattery();
			updateEntity.setDeviceSn(portableBattery.getDeviceSn());
			updateEntity.setLeaseType(PortableEnergyBatteryEnum.LeaseType.ShopService.index());
			updateEntity.setState(PortableEnergyBatteryEnum.State.Charging.index());
			updateEntity.setPlaceId(place.getId());
			updateEntity.setPlaceName(place.getName());
			updateEntity.setProvince(place.getProvince());
			updateEntity.setCity(place.getCity());
			updateEntity.setCityArea(place.getCityArea());
			updateEntity.setAreaCode(place.getAreaCode());
			updateEntity.setBindNote(bindNote);
			updateEntity.setDeployDate(new Date());

			JdbcSession.begin();
			try {
				if(dao.updateNotNull(updateEntity) > 0) {
					if(placeService.deployDevice(place.getId(),BXSCNConstants.BusinessTypeShop, 1)) {
						JdbcSession.commit();
						return true;
					}
				}
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}finally {
				JdbcSession.end();
			}
		}
		return false;
	}

	public boolean undeploy(PortableEnergyBattery portableBattery) throws LogicException {
		if(portableBattery != null ){
			Map<String,Object> data = new HashMap<>();
			data.put("deviceSn",portableBattery.getDeviceSn());
			data.put("state",PortableEnergyBatteryEnum.State.Stock.index());
			data.put("placeId",null);
			data.put("placeName",null);
			data.put("province",null);
			data.put("city",null);
			data.put("cityArea",null);
			data.put("areaCode",null);
			data.put("bindNote",null);
			data.put("deployDate",null);

			try {
				return dao.update(data) > 0;
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}
		}
		return false;
	}

	public void undeployByPlaceId(Long placeId){
		if(placeId != null){
			Integer pageNo = 1;
			Integer pageLimit = 300;

			PortableEnergyBatterySearch search = new PortableEnergyBatterySearch();
			search.setPlaceId(placeId);
			List<PortableEnergyBattery> energyBatteryList = this.findBySearch(search,pageNo,pageLimit);
			while (energyBatteryList != null && energyBatteryList.size() > 0){
				for(PortableEnergyBattery energyBattery : energyBatteryList){
					try {
						undeploy(energyBattery);
					} catch (LogicException e) {
						log.error(e.getMessage(),e);
					}
				}
				pageNo = pageNo + 1;
				energyBatteryList = this.findBySearch(search,pageNo,pageLimit);
			}
		}
	}

	public boolean updateBindNote(String deviceSn,String bindNote){
        if(StringTools.isNotBlank(deviceSn)) {
            Map<String, Object> data = new HashMap<>();
            data.put("deviceSn",deviceSn);
            data.put("bindNote",bindNote);

            try {
                return dao.update(data) >= 0;
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return false;
    }
	
	public boolean updateState(String deviceSn,Integer state) {
		PortableEnergyBattery updateEntity = new PortableEnergyBattery();
		updateEntity.setDeviceSn(deviceSn);
		updateEntity.setState(state);
		try {
			return dao.updateNotNull(updateEntity) > 0;
		} catch (SQLException e) {
			log.error(e.getMessage(), e);
		}
		return false;
	}
	
	/**
	 * 设置所属人
	 */
	public boolean belongUser(String deviceSn, Long userId) throws LogicException {
		if(StringTools.isNotBlank(deviceSn)){
			Map<String,Object> data = new HashMap<>();
			data.put("deviceSn",deviceSn);
			if(userId != null) {
				data.put("userId", userId);
				data.put("belongDate", new Date());
			}else {
				data.put("userId", null);
				data.put("belongDate",null);
			}

			try {
				return dao.update(data) > 0;
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}
		}
		return false;
	}

	public boolean changeLeaseType(String deviceSn) throws LogicException {
		if(StringTools.isNotBlank(deviceSn)) {
			PortableEnergyBattery battery = getByDeviceSn(deviceSn);
			if (battery == null) {
				throw new LogicException("未找到电池信息");
			}
			if(PortableEnergyBatteryEnum.LeaseType.ShopService.index().equals(battery.getLeaseType())){
				Map<String,Object> data = new HashMap<>();
				data.put("deviceSn",deviceSn);
				data.put("leaseType",PortableEnergyBatteryEnum.LeaseType.SelfService.index());
				data.put("placeId",null);
				data.put("placeName",null);
				data.put("province",null);
				data.put("city",null);
				data.put("cityArea",null);
				data.put("areaCode",null);

				try {
					return dao.update(data) > 0;
				} catch (SQLException e) {
					log.error(e.getMessage(),e);
				}
			}else if(PortableEnergyBatteryEnum.LeaseType.SelfService.index().equals(battery.getLeaseType())){
				Map<String,Object> data = new HashMap<>();
				data.put("deviceSn",deviceSn);
				data.put("leaseType",PortableEnergyBatteryEnum.LeaseType.ShopService.index());
				data.put("cabinetDeviceSn",null);
				data.put("slotNum",null);
				data.put("power",null);

				try {
					return dao.update(data) > 0;
				} catch (SQLException e) {
					log.error(e.getMessage(),e);
				}
			}
		}
		return false;
	}

	public boolean eject(String deviceSn){
		if(StringTools.isNotBlank(deviceSn)) {
			Map<String, Object> data = new HashMap<>();
			data.put("deviceSn",deviceSn);
			data.put("cabinetDeviceSn",null);
			data.put("slotNum",null);
			data.put("state", PortableEnergyBatteryEnum.State.Lease.index());
			data.put("lastHeartDate",new Date());

			try {
				return dao.update(data) > 0;
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}
		}
		return false;
	}

	public boolean lease(String deviceSn,String tradeNo,Date leaseDate){
		if(StringTools.isNotBlank(deviceSn)) {
			Conditions conditions = new Conditions(PortableEnergyBattery.class);
			conditions.and().is("deviceSn",deviceSn);
			conditions.and().is("state",PortableEnergyBatteryEnum.State.Charging.index());

			Map<String, Object> data = new HashMap<>();
			data.put("deviceSn",deviceSn);
			data.put("cabinetDeviceSn",null);
			data.put("slotNum",null);
			data.put("currentTradeNo",tradeNo);
			data.put("state", PortableEnergyBatteryEnum.State.Lease.index());
			data.put("lastLeaseDate",leaseDate);

			try {
				return dao.update(data) > 0;
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}
		}
		return false;
	}

	public boolean revert(String deviceSn){
		if(StringTools.isNotBlank(deviceSn)) {
			Map<String, Object> data = new HashMap<>();
			data.put("deviceSn",deviceSn);
			data.put("cabinetDeviceSn",null);
			data.put("slotNum",null);
			data.put("state", PortableEnergyBatteryEnum.State.Charging.index());
			data.put("power",null);

			try {
				return dao.update(data) > 0;
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}
		}
		return false;
	}

	public boolean lose(String deviceSn){
		if(StringTools.isNotBlank(deviceSn)) {
			Map<String, Object> data = new HashMap<>();
			data.put("deviceSn",deviceSn);
			data.put("cabinetDeviceSn",null);
			data.put("slotNum",null);
			data.put("state", PortableEnergyBatteryEnum.State.Charging.index());
			data.put("power",null);

			try {
				return dao.update(data) > 0;
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}
		}
		return false;
	}

	public boolean revert(String deviceSn,String cabinetDeviceSn,Integer slotNum,Double power){
		if(StringTools.isNotBlank(deviceSn)) {
			Map<String, Object> data = new HashMap<>();
			data.put("deviceSn",deviceSn);
			data.put("cabinetDeviceSn",cabinetDeviceSn);
			data.put("slotNum",slotNum);
			data.put("state", PortableEnergyBatteryEnum.State.Charging.index());
			data.put("power",power);
			data.put("lastHeartDate",new Date());

			try {
				return dao.update(data) > 0;
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}
		}
		return false;
	}

	public boolean updateDeviceSn(String newDeviceSn,String oldDeviceSn) throws LogicException{
		if(StringTools.isNotBlank(newDeviceSn) && StringTools.isNotBlank(oldDeviceSn)){
			if(newDeviceSn.length() < 6) {
				throw new LogicException("电池序列号需要5位数以上");
			}
			try {
				if(dao.updateDeviceSn(newDeviceSn,oldDeviceSn) > 0){
					return true;
				}
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}
		}
		return false;
	}

	public boolean deleteByDeviceSn(String deviceSn) throws LogicException {
		try {
			return dao.deleteById(deviceSn) > 0;
		} catch (SQLException e) {
			log.error(e.getMessage(),e);
		}
		return false;
	}
}
